package com.heo.protocol.packet;

import java.util.Date;

import org.apache.log4j.Logger;
import com.heo.util.ByteHelper;

/**
 * 基础数据包
 * 
 * @author zhangcf
 * @version 1.0
 * @date 2017-5-29
 * @param <T>
 */
public abstract class BasePacket
{
  public final int HEAD_LENGTH = 7;// 包头长7个字节

  protected String logHeader = "";
  protected String packetName = "";

  protected Date createTime = new Date();

  // 消息总长度(含消息头及消息体)
  protected int totalLength;// 协议定义的长度是2个字节，为了表示无符号的short，所以定义为int，然后在输出编码的时候输出short方式即可忽略高位字节
  // 命令ID或响应类型ID
  protected short commandId;
  // 消息流水号,顺序累加,步长为1,循环使用（一对请求和应答消息的流水号必须相同）
  protected int sequenceId;// 协议定义的长度是2个字节，为了表示无符号的short，所以定义为int，然后在输出编码的时候输出short方式即可忽略高位字节
  // 消息发送次数
  protected short sendCount = 0x01;// 消息的发送次数，1个字节

  public byte[] packetBody = null; // 具体数据

  public BasePacket()
  {
    createTime = new Date();
  }

  public void copyPacket(String logHeader, String packetName, SocketPacket packet)
  {
    this.logHeader = logHeader;
    this.packetName = packetName;
    this.totalLength = packet.getTotalLength();
    this.commandId = packet.getCommandId();
    this.sequenceId = packet.getSequenceId();
    this.sendCount = packet.getSendCount();
    this.packetBody = packet.getPacketBody();
    createTime = new Date();
  }

  public BasePacket(String packetName)
  {
    this.packetName = packetName;
    createTime = new Date();
  }

  /**
   * 根据数据包构造对象
   */
  public BasePacket(String logHeader, int totalLength, short commandId, int sequenceId,short sendCount, byte[] packetBody) throws Exception
  {
    this.logHeader = logHeader;
    this.totalLength = totalLength;
    this.commandId = commandId;
    this.sequenceId = sequenceId;
    this.packetBody = packetBody;
    this.sendCount = sendCount;
  }

  /**
   * 每个子类都要实现数据包的填充方法
   * 
   * @throws Exception
   */
  public abstract void makeBody() throws Exception;

  /**
   * 每次子类都要实现数据包拼接方法 获得数据包的包体
   * 
   * @return
   */
  public abstract byte[] getPacketBody();

  public abstract int getTotalLength();

  /**
   * 获得数据包的包头
   * 
   * @return
   */
  public byte[] getPacketHeader()
  {
    // 把包头中的totalLength和sequenceId转换成short类型，这样显示成无符号整数
    return ByteHelper.margeByte(ByteHelper.shortToByteArray((short) getTotalLength()), ByteHelper.shortToByteArray(commandId), ByteHelper.shortToByteArray((short) sequenceId), new byte[]{(byte)sendCount}, null, null, null, null, null, null);
  }

  /**
   * 获得整个数据包
   * 
   * @return
   */
  public byte[] getPacket()
  {
    return ByteHelper.margeByte(getPacketHeader(), getPacketBody(), null, null, null, null, null, null, null, null);
  }

  /**
   * 打印数据包的内容
   */
  public String toString()
  {
    return String.format("[%s] [%s]", ByteHelper.byteToHexString(getPacketHeader()), ByteHelper.byteToHexString(getPacketBody()));
  }

  /**
   * 获得数据包的名字
   * 
   * @return
   */
  public String getPacketName()
  {
    return packetName;
  }

  public short getCommandId()
  {
    return commandId;
  }

  public void setCommandId(short commandId)
  {
    this.commandId = commandId;
  }

  public int getSequenceId()
  {
    return sequenceId;
  }

  public void setSequenceId(int sequenceId)
  {
    this.sequenceId = sequenceId;
  }

  public String getLogHeader()
  {
    return logHeader;
  }

  public Date getCreateTime()
  {
    return createTime;
  }

  public short getSendCount()
  {
    return sendCount;
  }

  public void setSendCount(short sendCount)
  {
    this.sendCount = sendCount;
  }

}
